//
// Created by shen on 2024/10/30.
//


#include "DecoderBase.h"
void DecoderBase::Start() {
    if(m_Thread == nullptr) {
        StartDecodingThread();
    } else {
        std::unique_lock<std::mutex> lock(m_Mutex);
        m_DecoderState = STATE_DECODING;
        m_Cond.notify_all();
    }


}

void DecoderBase::StartDecodingThread() {
    m_Thread = new thread(DoAVDecoding, this);
    m_Thread->join();
}

int DecoderBase::Init(const char *url, AVMediaType mediaType) {

    strcpy(m_Url,url);
    m_MediaType=mediaType;
    return 0;

}

void DecoderBase::UpdateTimeStamp() {

    std::unique_lock<std::mutex> lock(m_Mutex);
    if (m_Frame->pkt_dts!=AV_NOPTS_VALUE){
        m_CurTimeStamp=m_Frame->pkt_dts;   //获取dts 解码时间

    }else if (m_Frame->pts!=AV_NOPTS_VALUE){
        m_CurTimeStamp = m_Frame->pts;  //获取pts 显示时间
    }else{
        m_CurTimeStamp = 0;
    }
    printf("beofore time = %d\n",m_CurTimeStamp);
    m_CurTimeStamp=(int64_t)(m_CurTimeStamp* av_q2d(m_AVFormatContext->streams[m_StreamIndex]->time_base)*1000);
    printf("time = %d\n",m_CurTimeStamp);
    if (m_SeekPosition>0&&m_SeekSuccess){
        m_StartTimeStamp = GetSysCurrentTime() - m_CurTimeStamp;
        m_SeekPosition = 0;
        m_SeekSuccess = false;
    }
}

void DecoderBase::UnInit() {
    if (m_Thread){
        Stop();
        m_Thread->join();
        delete m_Thread;
        m_Thread= nullptr;
    }
}
long DecoderBase::AVSync() {
    long curSysTime=GetSysCurrentTime();
    long elapsedTime=curSysTime-m_StartTimeStamp;

    long delay=0;
    //m_CurTimeStamp  当年播放的时间
    if (m_CurTimeStamp>elapsedTime){
        auto sleepTime=static_cast<unsigned int>(m_CurTimeStamp - elapsedTime);//ms
        sleepTime=sleepTime>DELAY_THRESHOLD?DELAY_THRESHOLD:  sleepTime;
        av_usleep(sleepTime * 1000);
    }
    delay = elapsedTime - m_CurTimeStamp;
    return delay;
}
int DecoderBase::DecodeOnePacket() {
    if(m_SeekPosition > 0) {
        int64_t seek_target= static_cast<int64_t>(m_SeekPosition * 1000000);//微妙
        int64_t seek_min = INT64_MIN;
        int64_t seek_max = INT64_MAX;
        int seek_ret = avformat_seek_file(m_AVFormatContext, -1, seek_min, seek_target, seek_max, 0);
        if (seek_ret < 0) {
            m_SeekSuccess = false;
        }else {
            if (-1 != m_StreamIndex) {
                avcodec_flush_buffers(m_AVCodecContext);
            }
            ClearCache();
            m_SeekSuccess = true;
        }
    }

    int result= av_read_frame(m_AVFormatContext,m_Packet);
    while(result==0){
        if(m_Packet->stream_index == m_StreamIndex) {
            if(avcodec_send_packet(m_AVCodecContext, m_Packet) == AVERROR_EOF) {
                result = -1;
                goto __EXIT;
            }

            int frameCount=0;
            while (avcodec_receive_frame(m_AVCodecContext,m_Frame)==0){
                UpdateTimeStamp();
                AVSync();
                OnFrameAvailable(m_Frame);
                frameCount ++;
            }
            if(frameCount > 0) {
                result = 0;
                goto __EXIT;
            }

        }
        av_packet_unref(m_Packet);
        result = av_read_frame(m_AVFormatContext, m_Packet);
    }
    __EXIT:
    av_packet_unref(m_Packet);
    return result;





}

void DecoderBase::DecodingLoop() {
    {
        std::unique_lock<std::mutex> lock(m_Mutex);
        m_DecoderState=STATE_DECODING;
        lock.unlock();
    }

    for (;;) {
        while (m_DecoderState==STATE_PAUSE){
            std::unique_lock<std::mutex> lock(m_Mutex);
            m_Cond.wait_for(lock,std::chrono::microseconds(10));
            m_StartTimeStamp=GetSysCurrentTime()-m_CurTimeStamp;
        }

        if (m_DecoderState==STATE_STOP){
            break;
        }

        if (m_StartTimeStamp==-1){
            m_StartTimeStamp=GetSysCurrentTime();
        }
        if (DecodeOnePacket()!=0){
            std::unique_lock<std::mutex> lock(m_Mutex);
            m_DecoderState=STATE_PAUSE;
        }
    }


}
void DecoderBase::Stop() {
    std::unique_lock<std::mutex> lock(m_Mutex);
    m_DecoderState = STATE_STOP;
    m_Cond.notify_all();
}

void DecoderBase::Pause() {
    std::unique_lock<std::mutex> lock(m_Mutex);
    m_DecoderState = STATE_PAUSE;
}

void DecoderBase::DoAVDecoding(DecoderBase *decoder) {
    do {
        printf("DoAVDecoding");
        if (decoder->InitFFDecoder()!=0){
            break;
        }
        decoder->OnDecoderReady();
        decoder->DecodingLoop();

    } while (false);
    decoder->UnInitDecoder();
    decoder->OnDecoderDone();

}
float DecoderBase::GetCurrentPosition() {
    return m_CurTimeStamp;
}
void DecoderBase::SeekToPosition(float position) {
    std::unique_lock<std::mutex> lock(m_Mutex);
    m_SeekPosition = position;
    m_DecoderState = STATE_DECODING;
    m_Cond.notify_all();
}

void DecoderBase::UnInitDecoder() {

    if(m_Frame != nullptr) {
        av_frame_free(&m_Frame);
        m_Frame = nullptr;
    }

    if(m_Packet != nullptr) {
        av_packet_free(&m_Packet);
        m_Packet = nullptr;
    }
    if(m_AVCodecContext != nullptr) {
        avcodec_close(m_AVCodecContext);
        avcodec_free_context(&m_AVCodecContext);
        m_AVCodecContext = nullptr;
        m_AVCodec = nullptr;
    }

    if(m_AVFormatContext != nullptr) {
        avformat_close_input(&m_AVFormatContext);
        avformat_free_context(m_AVFormatContext);
        m_AVFormatContext = nullptr;
    }


}
int DecoderBase::InitFFDecoder() {

    int result=-1;

    do {
        m_AVFormatContext=avformat_alloc_context();

        if (avformat_open_input(&m_AVFormatContext,m_Url, nullptr, nullptr)!=0){
            break;
        }

        if (avformat_find_stream_info(m_AVFormatContext, nullptr)<0){
            break;
        }

        printf("InitFFDecoder");
        for (int i = 0; i < m_AVFormatContext->nb_streams; ++i){
            if (m_AVFormatContext->streams[i]->codecpar->codec_type==m_MediaType) {
                m_StreamIndex = i;
                break;
            }
        }
        if (m_StreamIndex==-1){
            break;
        }
        AVCodecParameters *codecParameters=m_AVFormatContext->streams[m_StreamIndex]->codecpar;
        m_AVCodec= avcodec_find_decoder(codecParameters->codec_id);
        if (m_AVCodec== nullptr){
            break;
        }

        m_AVCodecContext= avcodec_alloc_context3(m_AVCodec);
        if (avcodec_parameters_to_context(m_AVCodecContext,codecParameters)!=0){
            break;
        }

        result= avcodec_open2(m_AVCodecContext,m_AVCodec, nullptr);

        if (result<0){
            break;
        }

        result=0;

        m_Duration=m_AVFormatContext->duration /AV_TIME_BASE* 1000;
        //创建 AVPacket 存放编码数据
        m_Packet=av_packet_alloc();
        //创建 AVFrame 存放解码后的数据
        m_Frame=av_frame_alloc();

    } while (false);

    return result;

}

